<?php

define("Core_Path",__DIR__);


class Lactone {

    protected static $Config;

    /**
     * @var $Spiders \lactone\Core\Spider\Spiders
     */
    public static $Spiders = false;

    /**
     * @var $log Log
     */
    public static $log     = false;

    const SPIDERLIVEACTION = 'SpiderLive';      //蜘蛛存活关键词
    const SPIDERLIVETIME   = 5;             //蜘蛛存活时间区间(秒)
    const SOCKET_TAG       = "||";       //socket数据通过TCP传输的时候,多次发送的数据可能一次就获取到了，所以这里需要把数据进行切割，需要有一个标识符

    /**
     * 初始化蜘蛛列表
     */
    public static function initSpider(){
        self::$Spiders = new \lactone\Core\Spider\Spiders();
    }

    /**
     * 初始化日志
     */
    public static function initLog(){
        $logConfig = self::getConfig('log');
        $defult = [
            'handler' =>'file',
            'name'    =>"Lactone",
            'ident'   =>'',
            'conf'    =>[],
            'level'   =>6
        ];

        $config = array_merge($defult,$logConfig);

        self::$log = Log::singleton($config['handler'],$config['name'],$config['ident'],$config['conf'],$config['level']);
    }

    /**
     * emerg错误
     * @param $message
     */
    public static function emerg($message){
        self::$log->emerg("[".getmypid()."]".$message);
    }

    /**
     * debug信息
     * @param $message
     */
    public static function debug($message){
        if(is_array($message)){
            self::$log->debug($message);
        }else{
            self::$log->debug("[".getmypid()."]".$message);
        }
    }

    /**
     * 警告信息
     * @param $message
     */
    public static function warning($message){
        self::$log->warning("[".getmypid()."]".$message);
    }

    /**
     * 提示信息
     * @param $message
     */
    public static function info($message){
        self::$log->info("[".getmypid()."]".$message);
    }

    public static function notice($message){
        self::$log->notice("[".getmypid()."]".$message);
    }

    /**
     * 把传递的Configs数组的值传递给Object
     * @param $object \Object
     * @param $Configs
     * @return bool
     */
    public static function initConfig($object,$Configs){
        if(!is_object($object) || !is_array($Configs)) return false;

        //系统配置初始化
        $ClassName= $object->getConfigName();
        if($GlobalConfig = self::getConfig($ClassName)){
            foreach($GlobalConfig as $key => $Config){
                $object->$key = $Config;
            }
        }
        //根据类名称的全称，设置配置的属性值
        $ClassName= $object->ClassName();
        if($GlobalConfig = self::getConfig($ClassName)){
            foreach($GlobalConfig as $key => $Config){
                $object->$key = $Config;
            }
        }

        //配置文件初始化
        if(empty($Configs)) return false;
        foreach($Configs as $key => $Config){
            $object->$key = $Config;
        }

    }

    /**
     * 生成实例
     */
    public static function CreateObject($Config){
        if(!isset($Config['class'])){
            throw new Exception("Need Set Class!");
            return false;
        }
        $Class = $Config['class'];
        unset($Config['class']);

        return (new $Class($Config));
    }

    /**
     * 存储全部的配置属性到本类中
     * @param $Config
     */
    public static function setConfigs($Config){
        self::$Config = $Config;
        //数据库初始化
        if(isset(self::$Config['db']) && isset(self::$Config['db']['connect'])){
            //数据库操作初始化
            ActiveRecord\Config::initialize(function($DbConfig) use($Config) {
                $DbConfig->set_model_directory(Core_Path . '/Models');
                $DbConfig->set_connections($Config['db']['connect']);
            });
        }
        return true;
    }

    /**
     * 获取配置变量中对应的值
     * @param $key
     * @return mixed
     */
    public static function getConfig($key){
        if(isset(self::$Config[$key])){
            return self::$Config[$key];
        }
        return NULL;
    }

    /**
     * 系统根据配置运行
     */
    public static function run(){

        self::initLog();

        set_error_handler(array("Lactone",'error_handle'),E_ALL);

        try{
            if( ($Run = self::getConfig('run')) &&  (isset($Run['initClass'])) && ($initClass = $Run['initClass'])){

                foreach($initClass as $Class){
                    $Object = self::CreateObject([
                        'class'=>$Class
                    ]);

                    $Object->run();
                }
            }else{
                echo 'Nothing To Do!System end!';
            }

        }catch (Exception $e){
            self::log_Exception($e);
        }

    }

    /**
     * 记录报错信息到日志中
     * @param Exception $e
     */
    public static function log_Exception(Exception $e){
        self::$log->emerg("[errfile:".$e->getFile()."] [errline:".$e->getLine()."] ".$e->getMessage());
    }

    /**
     * 错误处理，主要是记录日志信息
     * @param $errno
     * @param $errstr
     * @param $errfile
     * @param $errline
     * @return bool|void
     */
    public static function error_handle($errno, $errstr, $errfile, $errline){
        if (!(error_reporting() & $errno)) {
            // This error code is not included in error_reporting
            return;
        }

        switch ($errno) {
            case E_USER_ERROR:
                self::$log->warning("[errno:$errno] [errfile:$errfile] [errline:$errline] $errstr");
                exit(1);
                break;

            case E_USER_WARNING:
                self::$log->warning("[errno:$errno] [errfile:$errfile] [errline:$errline] $errstr");
                break;

            case E_USER_NOTICE:
                self::$log->notice("[errno:$errno] [errfile:$errfile] [errline:$errline] $errstr");
                break;

            default:
                self::$log->notice("unknow error [errno:$errno] [errfile:$errfile] [errline:$errline] $errstr");
                break;
        }

        /* Don't execute PHP internal error handler */
        return true;
    }

    /**
     * 保存子进程的pid信息
     */
    public static function saveProcessPid($Pid){
        $FILE = APP_PATH.'/PID';
        $fp = fopen($FILE,'a');

        if(flock($fp,LOCK_EX)){
            fwrite($fp," ".$Pid);
            flock($fp,LOCK_UN);
            fclose($fp);
            return true;
        }
    }
}